home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / Book Chapters / 03 - Advanced Graphics / Example 6 / demo.c < prev    next >
Text File  |  1995-03-06  |  16KB  |  555 lines

  1. //
  2. //    File: demo.c
  3. //
  4. //    This file contains the routines that control the demo.
  5. //
  6. //    2/19/95 -- Created by Mick
  7. //
  8.  
  9. // include files
  10.  
  11. #include "global.h"
  12.  
  13. #include <Palettes.h>
  14. #include <QDOffscreen.h>
  15.  
  16. #include "demo.h"
  17.  
  18. #include "main.h"
  19. #include "sprite.h"
  20. #include "update.h"
  21.  
  22. // defines for this file
  23.  
  24. #define kMaxObjects            10                // the maximum number of objects in the demo
  25. #define kClipRectInset        100            // the amount to inset the clip rect
  26.  
  27. // typedefs for this file
  28.  
  29. typedef struct
  30. {
  31.     tSpriteInfo *fSpriteInfo;                                            // the information on the sprite for this object
  32.     unsigned char fIsVisible;                                    // should we draw this object
  33.     unsigned char fWasVisible;                            // was this object visible last time?
  34.     signed long fXPos;                                                        // the x position of this object ( 16:16 fixed )
  35.     signed long fYPos;                                                        // the y position of this object ( 16:16 fixed )
  36.     signed long fDeltaX;                                                    // the x coord of the velocity of this object ( 16:16 fixed )
  37.     signed long fDeltaY;                                                    // the y coord of the velocity of this object ( 16:16 fixed )
  38.     signed short fIntXPos;                                            // the x position as an integer
  39.     signed short fIntYPos;                                            // the y position as an integer
  40. } tObjectInfo;
  41.  
  42. // global function declarations
  43.  
  44. void startupDemo( void );
  45. void shutdownDemo( void );
  46. void demoKey( unsigned char inKey );
  47. void doDemoFrame( void );
  48.  
  49. // global data owned by this file
  50.  
  51. GWorldPtr gOffscreenBuffer;                                        // the port and gdevice of the offscreen buffer
  52. PixMapHandle gOffscreenPixels;                                // the actual pixmap of the offscreen buffer
  53. Rect gOffscreenRect;                                                                // the size of the offscreen buffer
  54.  
  55. // local function declarations
  56.  
  57. static void moveObjects( void );                                                    // move all the objects
  58. static void blitToScreen( Rect *inCopyRect );            // copy data from offscreen to onscreen
  59. static void restoreBackground( void );                                // redraw the background
  60.  
  61. // static data
  62.  
  63. static tObjectInfo sObjects[ kMaxObjects ];                    // the data for all the objects
  64. static unsigned char sShowUpdateAreaFlag;            // should we show the update area?
  65. static unsigned char sStepMode;                                            // are we running step by step
  66.  
  67. // functions
  68.  
  69. //
  70. //    startupDemo -
  71. //
  72. //    Create and load all the buffers and data needed for the demo.
  73. //
  74.  
  75. void startupDemo( void )
  76. {
  77.     unsigned short indexCounter;                // a counter to scan the object array
  78.  
  79.     // create the offscreen gworld
  80.     NewGWorld( &gOffscreenBuffer, 8, &( gMainWindow->portRect ), gAppColorTable, ( GDHandle )kNil, keepLocal );
  81.  
  82.     // get the pixel map and rect
  83.     gOffscreenPixels = GetGWorldPixMap( gOffscreenBuffer );
  84.     gOffscreenRect = gMainWindow->portRect;
  85.  
  86.     // load the sprite
  87.     for( indexCounter = 0; indexCounter < kMaxObjects; indexCounter++ )
  88.         {
  89.             // load the sprites
  90.             sObjects[ indexCounter ].fSpriteInfo = loadSprite( kNumberOne + indexCounter );
  91.             
  92.             // give it a random location and velocity
  93.             sObjects[ indexCounter ].fIntXPos = Random() & 0x00FF;
  94.             sObjects[ indexCounter ].fIntYPos = Random() & 0x00FF;
  95.             sObjects[ indexCounter ].fXPos = ( sObjects[ indexCounter ].fIntXPos ) << 16;
  96.             sObjects[ indexCounter ].fYPos = ( sObjects[ indexCounter ].fIntYPos ) << 16;
  97.             sObjects[ indexCounter ].fDeltaX = Random() << 4;
  98.             sObjects[ indexCounter ].fDeltaY = Random() << 4;
  99.             
  100.             // initially, it is visible (but it was not last frame)
  101.             sObjects[ indexCounter ].fIsVisible = kTrue;
  102.             sObjects[ indexCounter ].fWasVisible = kFalse;
  103.         }
  104.     
  105.     // set the initial flags
  106.     sStepMode = kFalse;
  107.     sShowUpdateAreaFlag = kFalse;
  108. }
  109.  
  110.  
  111. //
  112. //    shutdownDemo -
  113. //
  114. //    Release all the memory used by the demo.
  115. //
  116.  
  117. void shutdownDemo( void )
  118. {
  119.     unsigned short indexCounter;                // a counter to scan the object array
  120.     
  121.     // dump the sprites
  122.     for( indexCounter = 0; indexCounter < kMaxObjects; indexCounter++ )
  123.         {
  124.             disposeSprite( sObjects[ indexCounter ].fSpriteInfo );
  125.         }
  126.     
  127.     // dump the offscreen gworld
  128.     DisposeGWorld( gOffscreenBuffer );
  129. }
  130.  
  131.  
  132. //
  133. //    demoKey -
  134. //
  135. //    Handle a key stroke -- allows the user to set options while the demo runs.
  136. //
  137.  
  138. void demoKey( unsigned char inKey )
  139. {
  140.     // depending on the key pressed
  141.     switch( inKey )
  142.         {
  143.             case 'u':        // turn show update on/off
  144.                 sShowUpdateAreaFlag = !sShowUpdateAreaFlag;
  145.                 break;
  146.             case 's':        // turn step mode on and off
  147.                 sStepMode = !sStepMode;
  148.                 break;
  149.             case ' ':        // step one frame (if we are in step mode)
  150.                 if ( sStepMode )
  151.                     {
  152.                         // allow one frame, by temporarily turning off step mode
  153.                         sStepMode = kFalse;
  154.                         doDemoFrame();
  155.                         sStepMode = kTrue;
  156.                     }
  157.                 break;
  158.             case '+':        // add more rects to the update
  159.                 increaseUpdateRects();
  160.                 break;
  161.             case '-':        // reduce the number of rects to update with
  162.                 decreaseUpdateRects();
  163.                 break;
  164.                 
  165.             case '1':        // turn this number on and off
  166.                 sObjects[ 0 ].fIsVisible = !sObjects[ 0 ].fIsVisible;
  167.                 break;
  168.             case '2':        // turn this number on and off
  169.                 sObjects[ 1 ].fIsVisible = !sObjects[ 1 ].fIsVisible;
  170.                 break;
  171.             case '3':        // turn this number on and off
  172.                 sObjects[ 2 ].fIsVisible = !sObjects[ 2 ].fIsVisible;
  173.                 break;
  174.             case '4':        // turn this number on and off
  175.                 sObjects[ 3 ].fIsVisible = !sObjects[ 3 ].fIsVisible;
  176.                 break;
  177.             case '5':        // turn this number on and off
  178.                 sObjects[ 4 ].fIsVisible = !sObjects[ 4 ].fIsVisible;
  179.                 break;
  180.             case '6':        // turn this number on and off
  181.                 sObjects[ 5 ].fIsVisible = !sObjects[ 5 ].fIsVisible;
  182.                 break;
  183.             case '7':        // turn this number on and off
  184.                 sObjects[ 6 ].fIsVisible = !sObjects[ 6 ].fIsVisible;
  185.                 break;
  186.             case '8':        // turn this number on and off
  187.                 sObjects[ 7 ].fIsVisible = !sObjects[ 7 ].fIsVisible;
  188.                 break;
  189.             case '9':        // turn this number on and off
  190.                 sObjects[ 8 ].fIsVisible = !sObjects[ 8 ].fIsVisible;
  191.                 break;
  192.             case '0':        // turn this number on and off
  193.                 sObjects[ 9 ].fIsVisible = !sObjects[ 9 ].fIsVisible;
  194.                 break;
  195.                 
  196.             case '!':        // freeze/unfreeze this number
  197.                 if ( sObjects[ 0 ].fDeltaX == 0 && sObjects[ 0 ].fDeltaY == 0 )
  198.                     {
  199.                         sObjects[ 0 ].fDeltaX = Random() << 4;
  200.                         sObjects[ 0 ].fDeltaY = Random() << 4;
  201.                     }
  202.                 else
  203.                     {
  204.                         sObjects[ 0 ].fDeltaX = 0;
  205.                         sObjects[ 0 ].fDeltaY = 0;
  206.                     }
  207.                 break;
  208.             case '@':        // freeze/unfreeze this number
  209.                 if ( sObjects[ 1 ].fDeltaX == 0 && sObjects[ 1 ].fDeltaY == 0 )
  210.                     {
  211.                         sObjects[ 1 ].fDeltaX = Random() << 4;
  212.                         sObjects[ 1 ].fDeltaY = Random() << 4;
  213.                     }
  214.                 else
  215.                     {
  216.                         sObjects[ 1 ].fDeltaX = 0;
  217.                         sObjects[ 1 ].fDeltaY = 0;
  218.                     }
  219.                 break;
  220.             case '#':        // freeze/unfreeze this number
  221.                 if ( sObjects[ 2 ].fDeltaX == 0 && sObjects[ 2 ].fDeltaY == 0 )
  222.                     {
  223.                         sObjects[ 2 ].fDeltaX = Random() << 4;
  224.                         sObjects[ 2 ].fDeltaY = Random() << 4;
  225.                     }
  226.                 else
  227.                     {
  228.                         sObjects[ 2 ].fDeltaX = 0;
  229.                         sObjects[ 2 ].fDeltaY = 0;
  230.                     }
  231.                 break;
  232.             case '$':        // freeze/unfreeze this number
  233.                 if ( sObjects[ 3 ].fDeltaX == 0 && sObjects[ 3 ].fDeltaY == 0 )
  234.                     {
  235.                         sObjects[ 3 ].fDeltaX = Random() << 4;
  236.                         sObjects[ 3 ].fDeltaY = Random() << 4;
  237.                     }
  238.                 else
  239.                     {
  240.                         sObjects[ 3 ].fDeltaX = 0;
  241.                         sObjects[ 3 ].fDeltaY = 0;
  242.                     }
  243.                 break;
  244.             case '%':        // freeze/unfreeze this number
  245.                 if ( sObjects[ 4 ].fDeltaX == 0 && sObjects[ 4 ].fDeltaY == 0 )
  246.                     {
  247.                         sObjects[ 4 ].fDeltaX = Random() << 4;
  248.                         sObjects[ 4 ].fDeltaY = Random() << 4;
  249.                     }
  250.                 else
  251.                     {
  252.                         sObjects[ 4 ].fDeltaX = 0;
  253.                         sObjects[ 4 ].fDeltaY = 0;
  254.                     }
  255.                 break;
  256.             case '^':        // freeze/unfreeze this number
  257.                 if ( sObjects[ 5 ].fDeltaX == 0 && sObjects[ 5 ].fDeltaY == 0 )
  258.                     {
  259.                         sObjects[ 5 ].fDeltaX = Random() << 4;
  260.                         sObjects[ 5 ].fDeltaY = Random() << 4;
  261.                     }
  262.                 else
  263.                     {
  264.                         sObjects[ 5 ].fDeltaX = 0;
  265.                         sObjects[ 5 ].fDeltaY = 0;
  266.                     }
  267.                 break;
  268.             case '&':        // freeze/unfreeze this number
  269.                 if ( sObjects[ 6 ].fDeltaX == 0 && sObjects[ 6 ].fDeltaY == 0 )
  270.                     {
  271.                         sObjects[ 6 ].fDeltaX = Random() << 4;
  272.                         sObjects[ 6 ].fDeltaY = Random() << 4;
  273.                     }
  274.                 else
  275.                     {
  276.                         sObjects[ 6 ].fDeltaX = 0;
  277.                         sObjects[ 6 ].fDeltaY = 0;
  278.                     }
  279.                 break;
  280.             case '*':        // freeze/unfreeze this number
  281.                 if ( sObjects[ 7 ].fDeltaX == 0 && sObjects[ 7 ].fDeltaY == 0 )
  282.                     {
  283.                         sObjects[ 7 ].fDeltaX = Random() << 4;
  284.                         sObjects[ 7 ].fDeltaY = Random() << 4;
  285.                     }
  286.                 else
  287.                     {
  288.                         sObjects[ 7 ].fDeltaX = 0;
  289.                         sObjects[ 7 ].fDeltaY = 0;
  290.                     }
  291.                 break;
  292.             case '(':        // freeze/unfreeze this number
  293.                 if ( sObjects[ 8 ].fDeltaX == 0 && sObjects[ 8 ].fDeltaY == 0 )
  294.                     {
  295.                         sObjects[ 8 ].fDeltaX = Random() << 4;
  296.                         sObjects[ 8 ].fDeltaY = Random() << 4;
  297.                     }
  298.                 else
  299.                     {
  300.                         sObjects[ 8 ].fDeltaX = 0;
  301.                         sObjects[ 8 ].fDeltaY = 0;
  302.                     }
  303.                 break;
  304.             case ')':        // freeze/unfreeze this number
  305.                 if ( sObjects[ 9 ].fDeltaX == 0 && sObjects[ 9 ].fDeltaY == 0 )
  306.                     {
  307.                         sObjects[ 9 ].fDeltaX = Random() << 4;
  308.                         sObjects[ 9 ].fDeltaY = Random() << 4;
  309.                     }
  310.                 else
  311.                     {
  312.                         sObjects[ 9 ].fDeltaX = 0;
  313.                         sObjects[ 9 ].fDeltaY = 0;
  314.                     }
  315.                 break;
  316.                 
  317.             default:        // unknown key
  318.                 SysBeep( 0 );
  319.                 break;
  320.         }
  321. }
  322.  
  323.  
  324. //
  325. //    doDemoFrame -
  326. //
  327. //    Move the demo ahead one frame -- move the sprites and draw.
  328. //
  329.  
  330. void doDemoFrame( void )
  331. {
  332.     CGrafPtr oldPort;                                        // the graf port that is in place when we are called
  333.     GDHandle oldDevice;                                // the gdevice that is in place when we are called
  334.     signed long indexCounter;            // a counter to scan all the objects
  335.     signed long rectCounter;            // a counter to scan all the rects
  336.     Rect updateRect;                                            // the rect that needs to be updated
  337.     Point drawPoint;                                            // where to draw the sprite
  338.     
  339.     // if we are in step mode, return
  340.     if ( sStepMode )
  341.         {
  342.             return;
  343.         }
  344.     
  345.     // save the current port and gdevice
  346.     GetGWorld( &oldPort, &oldDevice );
  347.     
  348.     // set the offscreen buffer as current ( and lock the pixel map )
  349.     SetGWorld( gOffscreenBuffer, ( GDHandle )kNil );
  350.     LockPixels( gOffscreenPixels );
  351.     
  352.     // restore the background
  353.     restoreBackground();
  354.     
  355.     // move the objects
  356.     moveObjects();
  357.     
  358.     // draw the sprites in each of the update rects
  359.     for( rectCounter = 0; rectCounter < getUpdateRectCount(); rectCounter++ )
  360.         {
  361.             // get one of the update rects
  362.             getUpdateRect( rectCounter, &updateRect );
  363.             
  364.             // if the user wants it, draw the update rect
  365.             if ( sShowUpdateAreaFlag )
  366.                 {
  367.                     FrameRect( &updateRect );
  368.                 }
  369.  
  370.             // setup to draw the sprites
  371.             startSpriteDraw( &updateRect, gOffscreenPixels );
  372.                         
  373.             // draw the sprites from back to front
  374.             for( indexCounter = kMaxObjects - 1; indexCounter >= 0; indexCounter-- )
  375.                 {
  376.                     if ( sObjects[ indexCounter ].fIsVisible )
  377.                         {
  378.                             drawPoint.h = ( sObjects[ indexCounter ].fIntXPos ) ;
  379.                             drawPoint.v = ( sObjects[ indexCounter ].fIntYPos );
  380.                             drawSprite( sObjects[ indexCounter ].fSpriteInfo, drawPoint );
  381.                         }
  382.                 }
  383.             
  384.             // shutdown the shape draw
  385.             endSpriteDraw();
  386.         }
  387.  
  388.     if ( sShowUpdateAreaFlag )
  389.         {
  390.             // copy the buffer to the screen
  391.             blitToScreen( &gOffscreenRect );            
  392.         }
  393.     else
  394.         {
  395.             // copy each of the update rects to the screen
  396.             for( rectCounter = 0; rectCounter < getUpdateRectCount(); rectCounter++ )
  397.                 {
  398.                     // get one of the update rects
  399.                     getUpdateRect( rectCounter, &updateRect );
  400.                 
  401.                     // copy the buffer to the screen
  402.                     blitToScreen( &updateRect );            
  403.                 }
  404.         }
  405.     
  406.     // restore the current port and gdevice
  407.     UnlockPixels( gOffscreenPixels );
  408.     SetGWorld( oldPort, oldDevice );
  409. }
  410.  
  411.  
  412. //
  413. //    moveObjects -
  414. //
  415. //    Move all the objects.
  416. //
  417.  
  418. void moveObjects( void )
  419. {
  420.     unsigned short indexCounter;            // a counter to scan all the objects
  421.     Rect objectRect;                                                            // the rectangle that bounds the object
  422.     
  423.     // clear the update area
  424.     clearUpdate();
  425.     
  426.     // concider each object
  427.     for( indexCounter = 0; indexCounter < kMaxObjects; indexCounter++ )
  428.         {
  429.             // if this object has no velocity and we are not displaying the update rects, we can ignore it
  430.             if ( sObjects[ indexCounter ].fDeltaX == 0 && sObjects[ indexCounter ].fDeltaY == 0 )
  431.                 {
  432.                     continue;
  433.                 }
  434.             
  435.             // if the object was visible last time
  436.             if ( sObjects[ indexCounter ].fWasVisible )
  437.                 {
  438.                     // determine the object's rect
  439.                     objectRect = ( sObjects[ indexCounter ].fSpriteInfo )->fSpriteRect;
  440.                     objectRect.left += sObjects[ indexCounter ].fIntXPos;
  441.                     objectRect.top += sObjects[ indexCounter ].fIntYPos;
  442.                     objectRect.right += sObjects[ indexCounter ].fIntXPos;
  443.                     objectRect.bottom += sObjects[ indexCounter ].fIntYPos;
  444.         
  445.                     // add the old rect to the update (so it will be erased)
  446.                     addRectToUpdate( &objectRect );
  447.                 }
  448.  
  449.             // apply the velocity
  450.             sObjects[ indexCounter ].fXPos += sObjects[ indexCounter ].fDeltaX;
  451.             sObjects[ indexCounter ].fYPos += sObjects[ indexCounter ].fDeltaY;
  452.             
  453.             // if the object has hit an edge, bounce it
  454.             if( sObjects[ indexCounter ].fXPos < ( gOffscreenRect.left << 16 ) )
  455.                 {
  456.                     sObjects[ indexCounter ].fDeltaX *= -1;
  457.                     sObjects[ indexCounter ].fXPos += ( gOffscreenRect.left << 16 ) - sObjects[ indexCounter ].fXPos;
  458.                 }
  459.             if( sObjects[ indexCounter ].fYPos < ( gOffscreenRect.top << 16 ) )
  460.                 {
  461.                     sObjects[ indexCounter ].fDeltaY *= -1;
  462.                     sObjects[ indexCounter ].fYPos += ( gOffscreenRect.top << 16 ) - sObjects[ indexCounter ].fYPos;
  463.                 }
  464.             if( sObjects[ indexCounter ].fXPos + 
  465.                     ( ( ( sObjects[ indexCounter ].fSpriteInfo )->fSpriteRect.right -
  466.                     ( sObjects[ indexCounter ].fSpriteInfo )->fSpriteRect.left ) << 16 ) >
  467.                     ( gOffscreenRect.right << 16 ) )
  468.                 {
  469.                     sObjects[ indexCounter ].fDeltaX *= -1;
  470.                     sObjects[ indexCounter ].fXPos += ( ( gOffscreenRect.right - 
  471.                             ( ( sObjects[ indexCounter ].fSpriteInfo )->fSpriteRect.right -
  472.                             ( sObjects[ indexCounter ].fSpriteInfo )->fSpriteRect.left ) ) << 16 ) - 
  473.                             sObjects[ indexCounter ].fXPos;
  474.                 }
  475.             if( sObjects[ indexCounter ].fYPos + 
  476.                     ( ( ( sObjects[ indexCounter ].fSpriteInfo )->fSpriteRect.bottom -
  477.                     ( sObjects[ indexCounter ].fSpriteInfo )->fSpriteRect.top ) << 16 ) >
  478.                     ( gOffscreenRect.bottom << 16 ) )
  479.                 {
  480.                     sObjects[ indexCounter ].fDeltaY *= -1;
  481.                     sObjects[ indexCounter ].fYPos += ( ( gOffscreenRect.bottom - 
  482.                             ( ( sObjects[ indexCounter ].fSpriteInfo )->fSpriteRect.bottom -
  483.                             ( sObjects[ indexCounter ].fSpriteInfo )->fSpriteRect.top ) ) << 16 ) - 
  484.                             sObjects[ indexCounter ].fYPos;
  485.                 }
  486.             
  487.             // if the object is visible
  488.             if( sObjects[ indexCounter ].fIsVisible )
  489.                 {
  490.                     // evaluate the fixed numbers to new integer positions
  491.                     sObjects[ indexCounter ].fIntXPos = ( sObjects[ indexCounter ].fXPos ) >> 16;
  492.                     sObjects[ indexCounter ].fIntYPos = ( sObjects[ indexCounter ].fYPos ) >> 16;
  493.                     
  494.                     // determine the object's rect
  495.                     objectRect = ( sObjects[ indexCounter ].fSpriteInfo )->fSpriteRect;
  496.                     objectRect.left += sObjects[ indexCounter ].fIntXPos;
  497.                     objectRect.top += sObjects[ indexCounter ].fIntYPos;
  498.                     objectRect.right += sObjects[ indexCounter ].fIntXPos;
  499.                     objectRect.bottom += sObjects[ indexCounter ].fIntYPos;
  500.         
  501.                     // add the new rect to the update (so it will be drawn)
  502.                     addRectToUpdate( &objectRect );
  503.                 }
  504.             
  505.             // record the this frame's visibility
  506.             sObjects[ indexCounter ].fWasVisible = sObjects[ indexCounter ].fIsVisible;
  507.         }
  508. }
  509.  
  510.  
  511. //
  512. //    blitToScreen -
  513. //
  514. //    This routine updates the screen from the offscreen buffer.
  515. //
  516.  
  517. void blitToScreen( Rect *inCopyRect )
  518. {
  519.     CGrafPtr oldPort;                    // the graf port that is in place when we are called
  520.     GDHandle oldDevice;            // the gdevice that is in place when we are called
  521.  
  522.     // save the current port and gdevice
  523.     GetGWorld( &oldPort, &oldDevice );
  524.  
  525.     // set the drawing environment to the screen
  526.     SetGWorld( ( CWindowPtr )gMainWindow, GetMainDevice() );
  527.  
  528.     // make sure that the fore and back colors are correct to prevent colorize mode
  529.     ForeColor( blackColor );
  530.     BackColor( whiteColor );
  531.     
  532.     // Copy the screen's color table seed into the source pixmap.
  533.     // This will minimize CopyBits' setup time.
  534.     ( *( ( *gOffscreenPixels )->pmTable ) )->ctSeed = ( *( ( *( ( *( GetGDevice() ) )->gdPMap ) )->pmTable ) )->ctSeed;
  535.  
  536.     // copy the buffer to the screen
  537.     CopyBits( ( BitMap * )( *gOffscreenPixels ), &( gMainWindow->portBits ), 
  538.             inCopyRect, inCopyRect, srcCopy, ( RgnHandle )kNil );
  539.  
  540.     // restore the current port and gdevice
  541.     SetGWorld( oldPort, oldDevice );
  542. }
  543.  
  544.  
  545. //
  546. //    restoreBackground -
  547. //
  548. //    This routine redraws the background over changed areas.
  549. //
  550.  
  551. void restoreBackground( void )
  552. {
  553.     // erase the entire offscreen
  554.     EraseRect( &gOffscreenRect );
  555. }